-
Notifications
You must be signed in to change notification settings - Fork 170
[ASRPass] Wrap all the global symbols into a module #1491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ASRPass] Wrap all the global symbols into a module #1491
Conversation
Yes, this is good. Once this passes tests, please ping me. |
76d3891
to
5923b99
Compare
99bd649
to
0003a20
Compare
src/libasr/codegen/asr_to_c.cpp
Outdated
visit_symbol(*struct_sym); | ||
array_types_decls += src; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need special handling of this global_symbols module? I was hoping that since it's just a regular module, it would not need any special handling like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, here in C backend, I think the visit_module is not yet implemented, except for the lfortran_intrinsics
module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. Probably this can be removed. I guess you can just do if(ASR::is_a<ASR::Module_t>(*item.second))
and call visit_Module(*ASR::down_cast<ASR::Module_t>(item.second))
inside the if
block by creating a new loop similar to the following,
lpython/src/libasr/codegen/asr_to_c.cpp
Lines 613 to 623 in 8f62ac4
for (auto &item : x.m_global_scope->get_scope()) { | |
if (ASR::is_a<ASR::Variable_t>(*item.second)) { | |
ASR::Variable_t *v = ASR::down_cast<ASR::Variable_t>(item.second); | |
unit_src_tmp = convert_variable_decl(*v); | |
unit_src += unit_src_tmp; | |
if(unit_src_tmp.size() > 0 && (!ASR::is_a<ASR::Const_t>(*v->m_type) || | |
v->m_intent == ASRUtils::intent_return_var )) { | |
unit_src += ";\n"; | |
} | |
} | |
} |
Please comment here if you face any blocker or issues while following this approach.
throw LCompilersException("Moving the symbol:`" + a.first + | ||
"` from global scope is not implemented yet"); | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't scalable. I would do it by writing a visitor in asdl_cpp.py
. Will you be able to try the class design and implement it? Give it a try for a couple of days, if not then we will merge this with a TODO
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this in TODO
src/libasr/pass/array_op.cpp
Outdated
@@ -182,6 +182,38 @@ class ArrayOpVisitor : public PassUtils::PassVisitor<ArrayOpVisitor> | |||
} | |||
} | |||
|
|||
void visit_Module(const ASR::Module_t &x) { | |||
if (strcmp(x.m_name, "_global_symbols") == 0) { | |||
// FIXME: this is a hack, we need to pass in a non-const `x`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try removing this if check. If it does not work, let's figure out the real bug why it doesn't work.
@@ -94,6 +94,38 @@ class CreateFunctionFromSubroutine: public PassUtils::PassVisitor<CreateFunction | |||
} | |||
} | |||
|
|||
void visit_Module(const ASR::Module_t &x) { | |||
if (strcmp(x.m_name, "_global_symbols") == 0) { | |||
// FIXME: this is a hack, we need to pass in a non-const `x`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
Let's see if we can just construct the new module, but then treat it like any other module, no special treatment. That would be the cleanest design. |
0003a20
to
6744ac5
Compare
b26f1ae
to
d374871
Compare
@Thirumalai-Shaktivel let me know when this is ready for review. |
Yup, I think I made the required changes. This is ready for review. |
Thanks! This requires a thorough review, I'll try to do it soon. It looks good at first sight though. @czgdp1807 can you also please review this? |
@@ -427,4 +427,5 @@ RUN(NAME comp_01 LABELS cpython llvm wasm wasm_x64) | |||
RUN(NAME bit_operations_i32 LABELS cpython llvm wasm wasm_x64) | |||
RUN(NAME bit_operations_i64 LABELS cpython llvm wasm) | |||
|
|||
RUN(NAME test_argv_01 LABELS llvm) # TODO: Test using CPython | |||
RUN(NAME test_argv_01 LABELS llvm) # TODO: Test using CPython | |||
RUN(NAME global_syms_01 LABELS cpython) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not llvm
and c
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In LLVM, the global lists are not yet handled. After merging this I will start working on it.
C: I didn't try it. How do I verify this works in C?
Using lpython integration_tests/global_syms_01.py --show-c
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In LLVM, the global lists are not yet handled. After merging this I will start working on it.
Any rough idea on how that will be managed. I think LLVM doesn't allow builder->CreateAlloca
in global scope. Worth researching approaches (implementation in LLVM is not at all required just a rough idea that there is a possibility to make it work in LLVM) once this before merging this because the success of this might rely on the possibility of actually using it in LLVM.
One approach in my mind is to create void*
typed global variables in the global scope and then bitcast them into list
LLVM type inside LLVM functions. That way any manipulation will happen inside LLVM functions.
Other approach is to see how clang++ does it for global variables like std::vector
in C++. For example the below code,
#include <iostream>
#include <vector>
std::vector<int> vec;
int main() {
return 0;
}
clang++
's LLVM output,
; ModuleID = '/Users/czgdp1807/lpython_project/debug.cpp'
source_filename = "/Users/czgdp1807/lpython_project/debug.cpp"
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "arm64-apple-macosx13.0.0"
%"class.std::__1::vector" = type { %"class.std::__1::__vector_base" }
%"class.std::__1::__vector_base" = type { i32*, i32*, %"class.std::__1::__compressed_pair" }
%"class.std::__1::__compressed_pair" = type { %"struct.std::__1::__compressed_pair_elem" }
%"struct.std::__1::__compressed_pair_elem" = type { i32* }
%"struct.std::__1::nullptr_t" = type { i8* }
%"struct.std::__1::__default_init_tag" = type { i8 }
%"class.std::__1::__vector_base_common" = type { i8 }
%"struct.std::__1::__compressed_pair_elem.0" = type { i8 }
%"class.std::__1::allocator" = type { i8 }
%"struct.std::__1::__non_trivial_if" = type { i8 }
@vec = global %"class.std::__1::vector" zeroinitializer, align 8
@__dso_handle = external hidden global i8
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_debug.cpp, i8* null }]
; Function Attrs: noinline ssp uwtable
define internal void @__cxx_global_var_init() #0 section "__TEXT,__StaticInit,regular,pure_instructions" {
%1 = call %"class.std::__1::vector"* @_ZNSt3__16vectorIiNS_9allocatorIiEEEC1Ev(%"class.std::__1::vector"* @vec)
%2 = call i32 @__cxa_atexit(void (i8*)* bitcast (%"class.std::__1::vector"* (%"class.std::__1::vector"*)* @_ZNSt3__16vectorIiNS_9allocatorIiEEED1Ev to void (i8*)*), i8* bitcast (%"class.std::__1::vector"* @vec to i8*), i8* @__dso_handle) #2
ret void
}
It can be seen that it creates global variables but initialises them inside a function. So you can do something similar for lists as well. Also, worth noting that we will have to create a function something like global_module_function
in LLVM and then call inside main
. But that should be doable.
C: I didn't try it. How do I verify this works in C?
Usinglpython integration_tests/global_syms_01.py --show-c
?
If LLVM is not enabled then C is not worth enabling. LLVM should always work with a given ASR design then other backends will automatically follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am approving it as I think this is clean enough at the ASR as well as LLVM/C level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@czgdp1807 the question here is how to handle module variables, as well as program variables. They are scoped to the module or program, but are essentially global. WASM and x86 have the same issue (@Shaikh-Ubaid and I discussed this a few times). It seems one must allocate the global variable (using the platform dependent mechanism), and then initialize it from the main function as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So seems like global statements are already being wrapped into a main function in the ASR itself? Well I would like to see what we will need to do when we enable llvm
for this test. Let’s merge it for now (I have approved earlier today).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me review this first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this is fine. I reviewed it and didn't find anything major.
Thanks for the approvals. |
d374871
to
458497f
Compare
* Move all the symbols from the global scope into the `_global_symbols` module * After applying this pass, there will only be two symbols in TranslationUnit, .ie., `Module` (_global_symbols) and `Program` (main_program) * `main_program` calls the `_lpython_main_program` (which contains the global statements) function from the module.
3642151
to
092a46e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fine to merge and iterate on later.
This PR aims to move all the symbols from the global scope (except main_program) into the Module (_global_scope).
Now the TranslationUnit contains only two symbols: Module (_global_scope) and a Program (main_program).
For more details and discussion: #1384